﻿// <copyright file="KMLStyleMap.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>

/////////////////////////////////////////////////////////////////////////////////////////////////
// KMLStyleMap.cs - A Tool For Reading XML 
// Project: IC.NETSOA- IC.NETDAL
//
// Language:    C#, .NET 4.0
// Platform:    Dell XPS m1530 Windows 7, VS 2010
// Author:      Don McGarry MITRE Rome
//              dmcgarry@mitre.org, (315) 838-2669
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace ICNET_KMLStyleEngine
{
  /// <summary>
  /// This enum functions as a flag for whether highlighting is used or not.
  /// </summary>
  public enum StyleStateEnum
  {
    /// <summary>
    /// Don't use highlighting.
    /// </summary>
    normal,

    /// <summary>
    /// Use highlighting.
    /// </summary>
    highlight
  }

  /// <summary>
  /// This class contains the methods used in converting XML into  KML
  /// </summary>
  public class KMLStyleMap : IXmlSerializable
  {
    /// <summary>
    /// The id of the message.
    /// </summary>
    private string id;

    /// <summary>
    /// A list of KML key/value pairs.
    /// </summary>
    private List<KMLPair> thePairs;

    #region Public Accessors
    [XmlIgnore]

    /// <summary>
    /// Gets the id. of a message.
    /// </summary>
    public string ID
    {
      get
      {
        return this.id;
      }
    }

    
    public List<string> StyleDependencies
    {
        get
        {
            List<string> dependencies = new List<string>();

            foreach (var pair in thePairs)
            {
                dependencies.Add(pair.Value);
            }

            return dependencies;
        }
    }

    #endregion

    #region Public Member Functions

    /// <summary>
    /// Makes sure that there is a key or styleurl associated with this object
    /// </summary>
    /// <returns>returns true unless there is neither a key nor a styleurl associated with this object.</returns>
    public bool HasAValue()
    {
      bool hasAValue = false;

      if (this.id != null)
      {
        hasAValue = true;
      }

      if (this.thePairs != null)
      {
        foreach (KMLPair pair in this.thePairs)
        {
          if (pair.HasAValue())
          {
            hasAValue = true;
          }
        }
      }

      return hasAValue;
    }

    /// <summary>
    /// Always returns null.
    /// </summary>
    /// <returns>returns null</returns>
    public XmlSchema GetSchema()
    {
      return null;
    }

    /// <summary>
    /// Reads an XML document.
    /// </summary>
    /// <param name="reader">an XMLreader that will be read thorugh by the method</param>
    public void ReadXml(XmlReader reader)
    {
      if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "StyleMap")
      {
        bool isEmptyElement = reader.IsEmptyElement;

        if (!isEmptyElement)
        {
          this.id = reader["id"];

          XmlReader innerReader = reader.ReadSubtree();

          this.ReadStyleMapXML(innerReader);

          // reader.Read();
        }
      }
    }

    /// <summary>
    /// Reads an XML Style Map.
    /// </summary>
    /// <param name="reader">An XMLreader that will be read thorugh by the method.</param>
    public void ReadStyleMapXML(XmlReader reader)
    {
      bool isEmptyElement = false;

      while (reader.Read())
      {
        if (reader.MoveToContent() == XmlNodeType.Element)
        {
          isEmptyElement = reader.IsEmptyElement;

          if (!isEmptyElement)
          {
            if (reader.LocalName == "Pair")
            {
              KMLPair pair = new KMLPair();

              XmlReader innerReader = reader.ReadSubtree();
              pair.ReadXml(innerReader);

              if (pair.HasAValue())
              {
                if (this.thePairs == null)
                {
                  this.thePairs = new List<KMLPair>();
                }

                this.thePairs.Add(pair);
              }
            }
          }
        }
      }
    }

    /// <summary>
    /// Outputs XML using the XMLwriter passed in.
    /// </summary>
    /// <param name="writer">an XMLwriter that performs the writing</param>
    public void WriteXml(XmlWriter writer)
    {
      if (this.id != null)
      {
        writer.WriteAttributeString("id", this.id);
      }

      foreach (KMLPair pair in this.thePairs)
      {
        writer.WriteStartElement("Pair");
        pair.WriteXml(writer);
        writer.WriteEndElement();
      }
    }

    #endregion
  }

  /// <summary>
  /// This class contains methods for dealing with a KML key/value pair
  /// </summary>
  public class KMLPair : IXmlSerializable
  {
   /// <summary>
   /// The key, which should be "normal" or "highlighting".
   /// </summary>
    private string key;

    /// <summary>
    /// The url for the style.
    /// </summary>
    private string styleUrl;

    /// <summary>
    /// Accesses the URL
    /// </summary>
    public string Value { get { return styleUrl; } }

    /// <summary>
    /// Makes sure that there is a key or styleurl associated with this object
    /// </summary>
    /// <returns>returns true unless there is neither a key nor a styleurl associated with this object.</returns>
    public bool HasAValue()
    {
      bool hasAValue = false;

      if (this.key != null)
      {
        hasAValue = true;
      }

      if (this.styleUrl != null)
      {
        hasAValue = true;
      }

      return hasAValue;
    }

    /// <summary>
    /// Always returns null.
    /// </summary>
    /// <returns>returns null.</returns>
    public XmlSchema GetSchema()
    {
      return null;
    }

    /// <summary>
    /// Reads the XML 
    /// </summary>
    /// <param name="reader">An XMLreader that will be used to read the object.</param>
    public void ReadXml(XmlReader reader)
    {
      if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Pair")
      {
        bool isEmptyElement = reader.IsEmptyElement;

        if (!isEmptyElement)
        {
          XmlReader innerReader = reader.ReadSubtree();

          this.ReadPairXML(innerReader);
        }
      }
    }

    /// <summary>
    /// A helper method for ReadXML
    /// </summary>
    /// <param name="reader">an XMLreader that will be used to do the reading.</param>
    public void ReadPairXML(XmlReader reader)
    {
      bool isEmptyElement = false;

      while (reader.Read())
      {
        if (reader.MoveToContent() == XmlNodeType.Element)
        {
          isEmptyElement = reader.IsEmptyElement;

          if (reader.LocalName == "key")
          {
            this.key = KMLStyle.GetElementStringValue(reader.ReadSubtree());
          }
          else if (reader.LocalName == "styleUrl")
          {
            this.styleUrl = KMLStyle.GetElementStringValue(reader.ReadSubtree());
          }
        }
      }
    }

    /// <summary>
    /// Outputs XML using the XMLwriter passed in.
    /// </summary>
    /// <param name="writer">an XMLwriter that performs the writing.</param>
    public void WriteXml(XmlWriter writer)
    {
      if (this.key != null)
      {
        writer.WriteElementString("key", this.key);
      }

      if (this.styleUrl != null)
      {
        writer.WriteElementString("styleUrl", this.styleUrl);
      }
    }
  }
}
